<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-alpha.65">
<title data-react-helmet="true">11. 依赖注入/控制反转 | Fur</title><meta data-react-helmet="true" name="docsearch:version" content="current,latest"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:title" content="11. 依赖注入/控制反转 | Fur"><meta data-react-helmet="true" name="description" content="11.1 依赖注入"><meta data-react-helmet="true" property="og:description" content="11.1 依赖注入"><meta data-react-helmet="true" property="og:url" content="https://furos.cn/docs/dependency-injection"><link data-react-helmet="true" rel="shortcut icon" href="/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://furos.cn/docs/dependency-injection"><link rel="stylesheet" href="/styles.8aef5b7b.css">
<link rel="preload" href="/styles.8352e18a.js" as="script">
<link rel="preload" href="/runtime~main.98e14d7d.js" as="script">
<link rel="preload" href="/main.04e1b7d6.js" as="script">
<link rel="preload" href="/1.72c59440.js" as="script">
<link rel="preload" href="/2.a2e0b0a9.js" as="script">
<link rel="preload" href="/3.054f69af.js" as="script">
<link rel="preload" href="/1be78505.da78ff7d.js" as="script">
<link rel="preload" href="/85.0018927c.js" as="script">
<link rel="preload" href="/f976f453.e1be0e0e.js" as="script">
<link rel="preload" href="/17896441.9aece880.js" as="script">
<link rel="preload" href="/5e077782.ea4c508a.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<nav class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><div aria-label="Navigation bar toggle" class="navbar__toggle" role="button" tabindex="0"><svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></div><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs/">Next</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/docs">文档</a><a class="navbar__item navbar__link" href="/blog">博客</a><a href="https://chinadot.net" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">社区</a></div><div class="navbar__items navbar__items--right"><a href="https://space.bilibili.com/695987967" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">视频</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">工具</a><ul class="dropdown__menu"><li><a target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">代码生成器</a></li></ul></div><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">看板</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">仓库</a><ul class="dropdown__menu"><li><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">Gitee</a></li><li><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="dropdown__link" position="left">GitHub</a></li></ul></div><div class="react-toggle react-toggle--disabled displayOnlyInLargeViewport_2aTZ"><div class="react-toggle-track"><div class="react-toggle-track-check"><span class="toggle_BsTx">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_BsTx">🌞</span></div></div><div class="react-toggle-thumb"></div><input type="checkbox" disabled="" aria-label="Dark mode toggle" class="react-toggle-screenreader-only"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div><div class="navbar-sidebar"><div class="navbar-sidebar__brand"><a class="navbar__brand" href="/"><img class="navbar__logo" src="/img/logo.png" alt="Fur Logo"><strong class="navbar__title">Fur</strong></a></div><div class="navbar-sidebar__items"><div class="menu"><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link">Versions</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link navbar__link--active" href="/docs">文档</a></li><li class="menu__list-item"><a class="menu__link" href="/blog">博客</a></li><li class="menu__list-item"><a href="https://chinadot.net" target="_blank" rel="noopener noreferrer" class="menu__link">社区</a></li><li class="menu__list-item"><a href="https://space.bilibili.com/695987967" target="_blank" rel="noopener noreferrer" class="menu__link">视频</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">工具</a><ul class="menu__list"><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link" position="left">代码生成器</a></li></ul></li><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="menu__link">看板</a></li><li class="menu__list-item"><a target="_blank" rel="noopener noreferrer" class="menu__link menu__link--sublist">仓库</a><ul class="menu__list"><li class="menu__list-item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">Gitee</a></li><li class="menu__list-item"><a href="https://github.com/MonkSoul/Fur" target="_blank" rel="noopener noreferrer" class="menu__link" position="left">GitHub</a></li></ul></li></ul></div></div></div></nav><div class="main-wrapper"><div class="docPage_2gpo"><div class="docSidebarContainer_3_JD" role="complementary"><div class="sidebar_2urC"><div class="menu menu--responsive menu_5FrY"><button aria-label="Open Menu" aria-haspopup="true" class="button button--secondary button--sm menu__button" type="button"><svg aria-label="Menu" class="sidebarMenuIcon_Dm3K" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 32 32" role="img" focusable="false"><title>Menu</title><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><ul class="menu__list"><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">1. 框架介绍</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/">1.1 介绍</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/author">1.2 关于作者</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/source">1.3 源码结构</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/reference">1.4 项目引用</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/get-start">2. 一分钟入门</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/appstartup">3. 应用启动</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">4. 配置与选项</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/configuration">4.1 配置</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/options">4.2 选项</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/dynamic-api-controller">5. 动态 WebAPI</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/specification-document">6. 规范化接口文档</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/friendly-exception">7. 友好异常处理</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/data-validation">8. 数据校验</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">9. 数据库操作指南</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext">9.1 数据库上下文</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-locator">9.2 数据库上下文定位器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/entity">9.3 数据库实体</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-repository">9.4 仓储模式</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-add">9.5 新增操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-update">9.6 更新操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-add-or-update">9.7 新增或更新操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-delete">9.8 删除操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-batch">9.9 批量操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-query">9.10 查询操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-hight-query">9.11 高级查询操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-view">9.12 视图操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-proc">9.13 存储过程操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-function">9.14 函数操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-sql">9.15 Sql 操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-sql-template">9.16 Sql 模板</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-sql-proxy">9.17 Sql 高级代理</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-multi-database">9.18 多数据库操作</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-db-first">9.19 数据库生成模型</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-code-first">9.20 模型生成数据库</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-seed-data">9.21 实体种子数据</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-audit">9.22 审计日志</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-filter">9.23 实体/全局查询筛选器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-Interceptor">9.24 数据库操作拦截器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/tran">9.25 事务和工作单元</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/dbcontext-read-write">9.26 读写分离/主从复制</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/split-db">9.27 分表分库</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/saas">10. SaaS 多租户</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active active" href="/docs/dependency-injection">11. 依赖注入/控制反转</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/object-mapper">12. 对象数据映射</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/cache">13. 分布式缓存</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/auth-control">14. 安全鉴权</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/cors">15. CORS 跨域</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/view-engine">16. 视图引擎</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/local-language">17. 多语言处理</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/event-bus">18. 事件总线</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/logging">19. 日志记录</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/http">20. 网络请求</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/process-service">21. 进程服务</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/job">22. 任务调度</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/signalr">23. 即时通讯</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/grpc">24. Grpc 服务</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/deploy">25. 托管部署</a></li><li class="menu__list-item"><a class="menu__link" href="/docs/devops">26. 持续部署集成</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">27. 测试指南</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/unittest">27.1 单元测试</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/performance">27.2 性能测试</a></li></ul></li><li class="menu__list-item"><a class="menu__link" href="/docs/contribute">28. 贡献指南</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#!">29. 常见问题</a><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/answer">29.1 常见问题</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/errors">29.2 常见错误</a></li><li class="menu__list-item"><a class="menu__link" tabindex="-1" href="/docs/gooduse">29.3 最佳实践</a></li></ul></li></ul></div></div></div><main class="docMainContainer_3EyW"><div class="container padding-vert--lg docItemWrapper_1EkI"><div class="row"><div class="col docItemCol_2ASc"><div class="docItemContainer_3QWW"><article><header><h1 class="docTitle_1Lrw">11. 依赖注入/控制反转</h1></header><div class="markdown"><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="111-依赖注入"></a>11.1 依赖注入<a aria-hidden="true" tabindex="-1" class="hash-link" href="#111-依赖注入" title="Direct link to heading">#</a></h2><p>所谓依赖注入，是指程序运行过程中，如果需要调用另一个对象协助时，无须在代码中创建被调用者，而是依赖于外部的注入。</p><p>通俗来讲，就是把有依赖关系的类放到容器中，然后在我们需要这些类时，容器自动解析出这些类的实例。</p><p>依赖注入最大的好处时实现类的解耦，利于程序拓展、单元测试、自动化模拟测试等。</p><p>依赖注入的英文为：<code>Dependency Injection</code>，简称 <code>DI</code></p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="112-控制反转"></a>11.2 控制反转<a aria-hidden="true" tabindex="-1" class="hash-link" href="#112-控制反转" title="Direct link to heading">#</a></h2><p>控制反转只是一个概念，也就是将创建对象实例的控制权（原本是程序员）从代码控制权剥离到 <code>IOC 容器</code> 中控制。</p><p>控制反转的英文为：<code>Inversion of Control</code>，简称 <code>IOC</code></p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="113-iocdi-优缺点"></a>11.3 <code>IOC/DI</code> 优缺点<a aria-hidden="true" tabindex="-1" class="hash-link" href="#113-iocdi-优缺点" title="Direct link to heading">#</a></h2><p>传统的代码，每个对象负责管理与自己需要依赖的对象，导致如果需要切换依赖对象的实现类时，需要修改多处地方。同时，过度耦合也使得对象难以进行单元测试。</p><ul><li><p>优点</p><ul><li>依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合（tight couple）的问题，是一种让代码实现松耦合（loose couple）的机制</li><li>松耦合让代码更具灵活性，能更好地应对需求变动，以及方便单元测试</li></ul></li><li><p>缺点</p><ul><li>目前主流的 <code>IOC/DI</code> 基本采用反射的方式来实现依赖注入，在一定程度会影响性能</li></ul></li></ul><div class="admonition admonition-important alert alert--info"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>特别说明</h5></div><div class="admonition-content"><p>在本章节不打算细讲 <code>依赖注入/控制反转</code> 具体实现和应用场景，想了解更多知识，可查阅 【<a href="https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0" target="_blank" rel="noopener noreferrer">ASP.NET Core 依赖注入</a>】 官方文档。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="114-依赖注入的三种方式"></a>11.4 依赖注入的三种方式<a aria-hidden="true" tabindex="-1" class="hash-link" href="#114-依赖注入的三种方式" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1141-构造方法注入"></a>11.4.1 构造方法注入<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1141-构造方法注入" title="Direct link to heading">#</a></h3><p>目前构造方法注入是依赖注入推荐使用方式。</p><ul><li><p>优点</p><ul><li>在构造方法中体现出对其他类的依赖，一眼就能看出这个类需要其他那些类才能工作</li><li>脱离了 IOC 框架，这个类仍然可以工作，POJO 的概念</li><li>一旦对象初始化成功了，这个对象的状态肯定是正确的</li></ul></li><li><p>缺点</p><ul><li>构造函数会有很多参数（Bad smell）</li><li>有些类是需要默认构造函数的，比如 MVC 框架的 Controller 类，一旦使用构造函数注入，就无法使用默认构造函数</li><li>这个类里面的有些方法并不需要用到这些依赖（Bad smell）</li></ul></li></ul><p>代码示例：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class FurService</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    private readonly IRepository _repository;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public FurService(IRepository repository)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        _repository = repository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1142-属性方式注入"></a>11.4.2 属性方式注入<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1142-属性方式注入" title="Direct link to heading">#</a></h3><p><strong>通过属性方式注入容易和类的实例属性混淆，不建议使用。</strong></p><ul><li><p>优点</p><ul><li>在对象的整个生命周期内，可以随时动态的改变依赖</li><li>非常灵活</li></ul></li><li><p>缺点</p><ul><li>对象在创建后，被设置依赖对象之前这段时间状态是不对的</li><li>不直观，无法清晰地表示哪些属性是必须的</li></ul></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class FurService</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public IRepository Repository { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1143-方法参数注入"></a>11.4.3 方法参数注入<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1143-方法参数注入" title="Direct link to heading">#</a></h3><p>方法参数注入的意思是在创建对象后，通过自动调用某个方法来注入依赖。</p><ul><li><p>优点：</p><ul><li>比较灵活</li></ul></li><li><p>缺点：</p><ul><li>新加入依赖时会破坏原有的方法签名，如果这个方法已经被其他很多模块用到就很麻烦</li><li>与构造方法注入一样，会有很多参数</li></ul></li></ul><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class FurService</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public Person GetById([FromServices]IRepository repository, int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return repository.Find(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="115-注册对象生存期"></a>11.5 注册对象生存期<a aria-hidden="true" tabindex="-1" class="hash-link" href="#115-注册对象生存期" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1151-暂时瞬时-生存期"></a>11.5.1 <code>暂时/瞬时</code> 生存期<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1151-暂时瞬时-生存期" title="Direct link to heading">#</a></h3><p>暂时生存期服务是每次从服务容器进行请求时创建的。 这种生存期适合轻量级、 无状态的服务。</p><p>在处理请求的应用中，在请求结束时会释放暂时服务。</p><p>通常我们使用 <code>ITransient</code> 接口依赖表示该生命周期。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1152-作用域-生存期"></a>11.5.2 <code>作用域</code> 生存期<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1152-作用域-生存期" title="Direct link to heading">#</a></h3><p>作用域生存期服务针对每个客户端请求（连接）创建一次。在处理请求的应用中，在请求结束时会释放有作用域的服务。</p><p>通常我们使用 <code>IScoped</code> 接口依赖表示该生命周期。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1153-单例-生存期"></a>11.5.3 <code>单例</code> 生存期<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1153-单例-生存期" title="Direct link to heading">#</a></h3><p>在首次请求它们时进行创建，之后每个后续请求都使用相同的实例。</p><p>通常我们使用 <code>ISingleton</code> 接口依赖表示该生命周期。</p><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>了解更多</h5></div><div class="admonition-content"><p>想了解更多 <code>服务生存期</code> 知识可查阅 <a href="https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0#service-lifetimes" target="_blank" rel="noopener noreferrer">ASP.NET Core - 依赖注入 - 服务生存期</a> 章节。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="116-内置依赖接口"></a>11.6 内置依赖接口<a aria-hidden="true" tabindex="-1" class="hash-link" href="#116-内置依赖接口" title="Direct link to heading">#</a></h2><p><code>Fur</code> 框架提供三个接口依赖分别对应不同的服务生存期：</p><ul><li><code>ITransient</code>：对应暂时/瞬时作用域服务生存期</li><li><code>IScoped</code>：对应请求作用域服务生存期</li><li><code>ISingleton</code>：对应单例作用域服务生存期</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="117-常见使用"></a>11.7 常见使用<a aria-hidden="true" tabindex="-1" class="hash-link" href="#117-常见使用" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1172-第一个例子"></a>11.7.2 第一个例子<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1172-第一个例子" title="Direct link to heading">#</a></h3><p>创建 <code>IBusinessService</code> 接口和 <code>BusinessService</code> 实现类，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Core;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DatabaseAccessor;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public interface IBusinessService</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Person Get(int id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class BusinessService : IBusinessService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IRepository&lt;Person&gt; _personRepository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public BusinessService(IRepository&lt;Person&gt; personRepository)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            _personRepository = personRepository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public Person Get(int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return _personRepository.Find(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>创建 <code>PersonController</code> 控制器，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Application;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry.Controllers</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [Route(&quot;api/[controller]&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [ApiController]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class PersonController : ControllerBase</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IBusinessService _businessService;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public PersonController(IBusinessService businessService)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            _businessService = businessService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [HttpGet]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public IActionResult Get(int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            var person = _businessService.Get(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return new JsonResult(person);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><img src="/img/di1.gif"><hr><p><strong>例子解说</strong></p><p><code>Fur</code> 框架提供了非常灵活且方便的实现依赖注入的方式，只需要实例类继承对应生存期的接口即可，这里继承了 <code>ITransient</code>，也就表明了这是一个 <code>暂时/瞬时</code> 作用域实例类。该类就可以作为被注入对象，同时也能注入其他接口对象。</p><p>上面的例子中，<code>BusinessService</code> 注入了 <code>IRepository&lt;Person&gt;</code> 仓储接口，同时 <code>PersonController</code> 控制器注入了 <code>IBusinessService</code> 接口。</p><p>这样 <code>PersonController</code> 和 <code>BusinessService</code> 之间就实现了解耦，不再依赖于具体的 <code>BusinessService</code> 实例。</p><p>这就是依赖注入/控制反转最经典的例子。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1173-注册泛型实例"></a>11.7.3 注册泛型实例<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1173-注册泛型实例" title="Direct link to heading">#</a></h3><p>创建 <code>IBusinessService&lt;T&gt;</code> 接口和 <code>BusinessService&lt;T&gt;</code> 实现类，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Core;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DatabaseAccessor;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public interface IBusinessService&lt;T&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        Person Get(int id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class BusinessService&lt;T&gt; : IBusinessService&lt;T&gt;, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IRepository&lt;Person&gt; _personRepository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public BusinessService(IRepository&lt;Person&gt; personRepository)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            _personRepository = personRepository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public Person Get(int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return _personRepository.Find(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>创建 <code>PersonController</code> 控制器，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Application;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry.Controllers</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [Route(&quot;api/[controller]&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [ApiController]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class PersonController : ControllerBase</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IBusinessService&lt;int&gt; _businessService;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public PersonController(IBusinessService&lt;int&gt; businessService)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            _businessService = businessService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [HttpGet]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public IActionResult Get(int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            var person = _businessService.Get(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return new JsonResult(person);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1174-一个接口多个实现"></a>11.7.4 一个接口多个实现<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1174-一个接口多个实现" title="Direct link to heading">#</a></h3><p>默认情况下，一个接口只对应一个实现类，但有些特殊情况，需要需要多个实现类注册同一个接口，如 <code>DbContext</code> 多数据库情况。</p><p>这个时候我们可以通过依赖注入 <code>Func&lt;string, IPrivateDependency, object&gt;</code> 委托来解析多个实例，其中委托的参数分别为：</p><ul><li>参数 1：<code>string</code> 类型，不同实现类唯一标识，默认为 <code>nameof(实现类)</code> 名称</li><li>参数 2：<code>Type</code> 类型，<code>IPrivateDependency</code> 派生接口，也就是 <code>ITransient</code>、<code>IScoped</code>、<code>ISingleton</code></li><li>返回值：<code>object</code> 类型，返回具体的实现类实例</li></ul><p>创建 <code>IBusinessService</code> 接口和 <code>BusinessService</code>、<code>OtherBusinessService</code> 两个实现类，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public interface IBusinessService</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        string GetName();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class BusinessService : IBusinessService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string GetName()</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return &quot;我是：&quot; + nameof(BusinessService);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class OtherBusinessService : IBusinessService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string GetName()</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return &quot;我是：&quot; + nameof(OtherBusinessService);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>创建 <code>ValueController</code> 控制器，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Application;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using System;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry.Controllers</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [Route(&quot;api/[controller]&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [ApiController]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class ValueController : ControllerBase</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IBusinessService _businessService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IBusinessService _otherBusinessService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public ValueController(Func&lt;string, ITransient, object&gt; resolveNamed)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            _businessService = resolveNamed(&quot;BusinessService&quot;, default) as IBusinessService;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            _otherBusinessService = resolveNamed(&quot;OtherBusinessService&quot;, default) as IBusinessService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [HttpGet]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public string GetName()</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return _businessService.GetName() + &quot;----------&quot; + _otherBusinessService.GetName();</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><img src="/img/di2.gif"><div class="admonition admonition-tip alert alert--success"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>小知识</h5></div><div class="admonition-content"><p>如果需要自定义解析名称，只需要贴 <code>[Injection(Named = &quot;名称&quot;)]</code> 即可，如：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [Injection(Named = &quot;BusName1&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class BusinessService : IBusinessService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // ...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    [Injection(Named = &quot;BusName2&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class OtherBusinessService : IBusinessService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        // ...</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>解析服务：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">_businessService = resolveNamed(&quot;BusName1&quot;, default) as IBusinessService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">_otherBusinessService = resolveNamed(&quot;BusName2&quot;, default) as IBusinessService;</span></div></div></div></div></div></div></div><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1175-无接口方式"></a>11.7.5 无接口方式<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1175-无接口方式" title="Direct link to heading">#</a></h3><p>有些时候，我们不想定义接口，而是想把实例类作为可依赖注入的对象，如 MVC 中的控制器。</p><p>创建 <code>SelfService</code> 实例类，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Core;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DatabaseAccessor;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class SelfService : ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly IRepository&lt;Person&gt; _personRepository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public SelfService(IRepository&lt;Person&gt; personRepository)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            _personRepository = personRepository;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public Person Get(int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return _personRepository.Find(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>创建 <code>ValueController</code> 控制器，代码如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Application;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Fur.Core;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using Microsoft.AspNetCore.Mvc;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Web.Entry.Controllers</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [Route(&quot;api/[controller]&quot;)]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    [ApiController]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public class ValueController : ControllerBase</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        private readonly SelfService _selfService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        public ValueController(SelfService selfService)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            _selfService = selfService;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        [HttpGet]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public Person Get(int id)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">            return _selfService.Get(id);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="118-injection-特性配置"></a>11.8 <code>[Injection]</code> 特性配置<a aria-hidden="true" tabindex="-1" class="hash-link" href="#118-injection-特性配置" title="Direct link to heading">#</a></h2><p><code>Fur</code> 框架提供 <code>[Injection]</code> 特性可以改变注册方式，同时还能配置 <code>AOP</code> 拦截。</p><p><code>[Injection]</code> 提供以下配置支持：</p><ul><li><code>Action</code>：配置注册行为，<code>InjectionActions</code> 类型，可选值：<ul><li><code>Add</code>：<strong>默认值</strong>，表示无限制添加注册服务，该方式支持一个接口多个实现</li><li><code>TryAdd</code>：表示注册已存在则跳过注册</li></ul></li><li><code>Pattern</code>：配置注册选项，<code>InjectionPatterns</code> 类型，可选值：<ul><li><code>Self</code>：只注册自己</li><li><code>FirstInterface</code>：只注册第一个接口</li><li><code>SelfWithFirstInterface</code>：注册自己和第一个接口，<strong>默认值</strong></li><li><code>ImplementedInterfaces</code>：注册所有接口</li><li><code>All</code>：注册自己包括所有接口</li></ul></li><li><code>Named</code>：配置实例别名，通过别名可以解析接口，如同一个接口有多个实现，那么可以通过别名解析不同的实现，默认只为实现类的类名</li><li><code>Order</code>：注册排序，数字越大，则越在最后注册，默认 <code>0</code></li><li><code>Proxy</code>：配置代理拦截类型，也就是 <code>AOP</code>，<strong>代理类型必须继承 <code>DispatchProxy</code> 类和 <code>IDispatchProxy</code> 接口</strong>，无默认值</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="119-自定义高级注册"></a>11.9 自定义高级注册<a aria-hidden="true" tabindex="-1" class="hash-link" href="#119-自定义高级注册" title="Direct link to heading">#</a></h2><p>默认情况下，<code>Fur</code> 提供的注册方式可以满足大多数依赖注入的需求，如有特别注册需求，只需要在 <code>Startup</code> 中配置即可，如：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">services.AddScoped(typeof(ISpecService), provider = &gt; {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    // 自定义任何创建实例的方式</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    var instance = new SpecService();  // 或者可以通过 AOP插件返回代理实例</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    return instance;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">});</span></div></div></div></div></div><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>补充说明</h5></div><div class="admonition-content"><p><code>Fur</code> 框架中的 <code>AppDbContext</code> 数据库上下文还有 <code>ISqlDispatchProxy</code> 都是通过这种方式创建的。</p></div></div><div class="admonition admonition-tip alert alert--success"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>知识导航</h5></div><div class="admonition-content"><p>想了解更多自定义高级中注册，可查阅 【<a href="https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0" target="_blank" rel="noopener noreferrer">ASP.NET Core 依赖注入</a>】 官方文档。</p></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1110-appsettingsjson-配置注册"></a>11.10 <code>appsettings.json</code> 配置注册<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1110-appsettingsjson-配置注册" title="Direct link to heading">#</a></h2><p>除了在代码中实现依赖注入，也可以实现动态依赖注入，无需修改代码或重新编译即可实现热拔插（插件）效果。配置如下：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-json codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">&quot;DependencyInjectionSettings&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">&quot;Definitions&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Interface&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Fur.Application;Fur.Application.ITestService&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Service&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Fur.Application;Fur.Application.TestService&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;RegisterType&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Transient&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Action&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Add&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Pattern&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;SelfWithFirstInterface&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Named&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;TestService&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Order&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token property">&quot;Proxy&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Fur.Application;Fur.Application.LogDispathProxy&quot;</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></div></div></div></div><p>配置说明：</p><ul><li><code>DependencyInjectionSettings</code>：依赖注入配置根节点<ul><li><code>Definitions</code>：动态依赖注入配置节点，<code>ExternalService</code> 数组类型<ul><li><code>ExternalService</code>：配置单个依赖注入信息<ul><li><code>Interface</code>：配置依赖接口信息，格式：<code>程序集名称;接口完整名称</code>，如：<code>Fur.Application;Fur.Application.ITestService</code></li><li><code>Service</code>：配置接口实现信息，格式同上</li><li><code>RegisterType</code>：配置依赖注入的对象生存期，取值：<code>Transient</code>，<code>Scoped</code>，<code>Singleton</code></li><li><code>Action</code>：注册行为，可选值：<code>Add</code>，<code>TryAdd</code>，参见 <a href="#118-injection-%E7%89%B9%E6%80%A7%E9%85%8D%E7%BD%AE">#118-injection-特性配置</a></li><li><code>Pattern</code>：注册选项，参见 <a href="#118-injection-%E7%89%B9%E6%80%A7%E9%85%8D%E7%BD%AE">#118-injection-特性配置</a></li><li><code>Named</code>：注册别名，参见 <a href="#118-injection-%E7%89%B9%E6%80%A7%E9%85%8D%E7%BD%AE">#118-injection-特性配置</a></li><li><code>Order</code>：注册排序，参见 <a href="#118-injection-%E7%89%B9%E6%80%A7%E9%85%8D%E7%BD%AE">#118-injection-特性配置</a></li><li><code>Proxy</code>：配置代理拦截，，格式：<code>程序集名称;代理类完整名称</code>，参见 <a href="#118-injection-%E7%89%B9%E6%80%A7%E9%85%8D%E7%BD%AE">#118-injection-特性配置</a></li></ul></li></ul></li></ul></li></ul><div class="admonition admonition-important alert alert--info"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>关于外部程序集</h5></div><div class="admonition-content"><p>如果动态注入的对象是外部程序集，那么首先先注册外部程序集：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-json codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token property">&quot;AppSettings&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token property">&quot;ExternalAssemblies&quot;</span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">&quot;外部程序集名称&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">&quot;Taobao.Pay&quot;</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// 支持多个</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span></div></div></div></div></div></div></div><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1111-注册顺序和优先级"></a>11.11 注册顺序和优先级<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1111-注册顺序和优先级" title="Direct link to heading">#</a></h2><p><code>Fur</code> 框架中，默认注册顺序是按照程序集扫描顺序进行注册，如果需要改变注册顺序，可通过 <code>[Injection(Order)]</code> 特性指定，<code>Order</code> 值越大，则越在最后注册。</p><p>另外 <code>appsettings.json</code> 配置的优先级最大，<code>appsettings.json</code> 配置的注册会覆盖之前所有注册。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1112-aop-注册拦截"></a>11.12 <code>Aop</code> 注册拦截<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1112-aop-注册拦截" title="Direct link to heading">#</a></h2><p><code>AOP</code> 是非常重要的思想和技术，也就是 <code>面向切面</code> 编程，可以让我们在不改动原来代码的情况下进行动态篡改业务代码。</p><p>在 <code>Fur</code> 框架中，实现 <code>Aop</code> 非常简单，如：</p><p>假设我们有 <code>ITestService</code> 和 <code>TestService</code> 两个类型：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class ITestService</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    string SayHello(string word);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class TestService: ITestService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string SayHello(string word)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return $&quot;Hello {word}&quot;;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>现在我们有一个需求，我们希望调用 <code>SayHello</code> 的时候可以记录日志和权限控制（之前没有考虑到的需求）。</p><p>这个时候我们只需要创建一个代理类即可，如 <code>LogDispatchProxy</code></p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using Fur.DependencyInjection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">using System;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">using System.Reflection;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">namespace Fur.Application</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">    public class LogDispatchProxy : DispatchProxy, IDispatchProxy</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 当前服务实例</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public object Target { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 服务提供器，可以用来解析服务，如：Services.GetService()</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        public IServiceProvider Services { get; set; }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// 拦截方法</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;/summary&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;param name=&quot;targetMethod&quot;&gt;&lt;/param&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;param name=&quot;args&quot;&gt;&lt;/param&gt;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        /// &lt;returns&gt;&lt;/returns&gt;</span></div><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">        protected override object Invoke(MethodInfo targetMethod, object[] args)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            Console.WriteLine(&quot;SayHello 方法被调用了&quot;);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            var result = targetMethod.Invoke(Target, args);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            Console.WriteLine(&quot;SayHello 方法返回值：&quot; + result);</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">            return result;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>之后我们只需要为 <code>TestService</code> 增加 <code>[Injection]</code> 特性即可，如：</p><div class="mdxCodeBlock_1XEh"><div class="codeBlockContent_1u-d"><button type="button" aria-label="Copy code to clipboard" class="copyButton_10dd">Copy</button><div tabindex="0" class="prism-code language-cs codeBlock_3iAC"><div class="codeBlockLines_b7E3" style="color:#bfc7d5;background-color:#292d3e"><div class="token-line docusaurus-highlight-code-line" style="color:#bfc7d5"><span class="token plain">[Injection(Proxy = typeof(LogDispatchProxy))]</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">public class TestService: ITestService, ITransient</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    public string SayHello(string word)</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">        return $&quot;Hello {word}&quot;;</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">    }</span></div><div class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></div></div></div></div></div><p>之后 <code>SayHello</code> 方法被调用的时候就可以实现动态拦截了，比如这里写日志。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="11121-aop-的作用"></a>11.12.1 <code>AOP</code> 的作用<a aria-hidden="true" tabindex="-1" class="hash-link" href="#11121-aop-的作用" title="Direct link to heading">#</a></h3><p>这种面向切面的能力（动态拦截/代理）可以实现很多很多功能，如：</p><ul><li>动态日志记录</li><li>动态修改参数</li><li>动态修改返回值</li><li>动态方法重定向</li><li>动态修改代码逻辑</li><li>动态实现异常监听</li></ul><p>还可以做更多更多的事情。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2cZh" id="1113-反馈与建议"></a>11.13 反馈与建议<a aria-hidden="true" tabindex="-1" class="hash-link" href="#1113-反馈与建议" title="Direct link to heading">#</a></h2><div class="admonition admonition-note alert alert--secondary"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="16" viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>与我们交流</h5></div><div class="admonition-content"><p>给 Fur 提 <a href="https://gitee.com/monksoul/Fur/issues/new?issue" target="_blank" rel="noopener noreferrer">Issue</a>。</p></div></div></div></article><div class="margin-vert--xl"><div class="row"><div class="col"><a href="https://gitee.com/monksoul/Fur/tree/main/handbook/docs/dependency-injection.mdx" target="_blank" rel="noreferrer noopener"><svg fill="currentColor" height="1.2em" width="1.2em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 40 40" style="margin-right:0.3em;vertical-align:sub"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div></div></div><div class="margin-vert--lg"><nav class="pagination-nav" aria-label="Blog list page navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/docs/saas"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« 10. SaaS 多租户</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/docs/object-mapper"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">12. 对象数据映射 »</div></a></div></nav></div></div></div><div class="col col--3"><div class="tableOfContents_3SO_"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#111-依赖注入" class="table-of-contents__link">11.1 依赖注入</a></li><li><a href="#112-控制反转" class="table-of-contents__link">11.2 控制反转</a></li><li><a href="#113-iocdi-优缺点" class="table-of-contents__link">11.3 <code>IOC/DI</code> 优缺点</a></li><li><a href="#114-依赖注入的三种方式" class="table-of-contents__link">11.4 依赖注入的三种方式</a><ul><li><a href="#1141-构造方法注入" class="table-of-contents__link">11.4.1 构造方法注入</a></li><li><a href="#1142-属性方式注入" class="table-of-contents__link">11.4.2 属性方式注入</a></li><li><a href="#1143-方法参数注入" class="table-of-contents__link">11.4.3 方法参数注入</a></li></ul></li><li><a href="#115-注册对象生存期" class="table-of-contents__link">11.5 注册对象生存期</a><ul><li><a href="#1151-暂时瞬时-生存期" class="table-of-contents__link">11.5.1 <code>暂时/瞬时</code> 生存期</a></li><li><a href="#1152-作用域-生存期" class="table-of-contents__link">11.5.2 <code>作用域</code> 生存期</a></li><li><a href="#1153-单例-生存期" class="table-of-contents__link">11.5.3 <code>单例</code> 生存期</a></li></ul></li><li><a href="#116-内置依赖接口" class="table-of-contents__link">11.6 内置依赖接口</a></li><li><a href="#117-常见使用" class="table-of-contents__link">11.7 常见使用</a><ul><li><a href="#1172-第一个例子" class="table-of-contents__link">11.7.2 第一个例子</a></li><li><a href="#1173-注册泛型实例" class="table-of-contents__link">11.7.3 注册泛型实例</a></li><li><a href="#1174-一个接口多个实现" class="table-of-contents__link">11.7.4 一个接口多个实现</a></li><li><a href="#1175-无接口方式" class="table-of-contents__link">11.7.5 无接口方式</a></li></ul></li><li><a href="#118-injection-特性配置" class="table-of-contents__link">11.8 <code>[Injection]</code> 特性配置</a></li><li><a href="#119-自定义高级注册" class="table-of-contents__link">11.9 自定义高级注册</a></li><li><a href="#1110-appsettingsjson-配置注册" class="table-of-contents__link">11.10 <code>appsettings.json</code> 配置注册</a></li><li><a href="#1111-注册顺序和优先级" class="table-of-contents__link">11.11 注册顺序和优先级</a></li><li><a href="#1112-aop-注册拦截" class="table-of-contents__link">11.12 <code>Aop</code> 注册拦截</a><ul><li><a href="#11121-aop-的作用" class="table-of-contents__link">11.12.1 <code>AOP</code> 的作用</a></li></ul></li><li><a href="#1113-反馈与建议" class="table-of-contents__link">11.13 反馈与建议</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="row footer__links"><div class="col footer__col"><h4 class="footer__title">文档</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/docs/get-start">入门</a></li><li class="footer__item"><a class="footer__link-item" href="/docs">指南</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">社区</h4><ul class="footer__items"><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/issues" target="_blank" rel="noopener noreferrer" class="footer__link-item">讨论</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur/board" target="_blank" rel="noopener noreferrer" class="footer__link-item">看板</a></li></ul></div><div class="col footer__col"><h4 class="footer__title">更多</h4><ul class="footer__items"><li class="footer__item"><a class="footer__link-item" href="/blog">博客</a></li><li class="footer__item"><a href="https://gitee.com/monksoul/Fur" target="_blank" rel="noopener noreferrer" class="footer__link-item">仓库</a></li></ul></div></div><div class="text--center"><div>Copyright © 2020 Fur, Baiqian Co.,Ltd.</div></div></div></footer></div>
<script src="/styles.8352e18a.js"></script>
<script src="/runtime~main.98e14d7d.js"></script>
<script src="/main.04e1b7d6.js"></script>
<script src="/1.72c59440.js"></script>
<script src="/2.a2e0b0a9.js"></script>
<script src="/3.054f69af.js"></script>
<script src="/1be78505.da78ff7d.js"></script>
<script src="/85.0018927c.js"></script>
<script src="/f976f453.e1be0e0e.js"></script>
<script src="/17896441.9aece880.js"></script>
<script src="/5e077782.ea4c508a.js"></script>
</body>
</html>